#include <iostream>
#include <cstring>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
using namespace std;

const string fifo = "./myfifo";
const mode_t mode = 0666;

void ReadFifo(int fd)
{
    char buf[64];
    int n = read(fd,buf,sizeof(buf));
    if(n > 0)
    {
        cout << "我读取到了 " << buf << endl; 
    }
    else if(n == 0)
    {
        cout << "对方关闭" << endl;
    }
    else
    {
        cout << "errno = " << errno << ", " << strerror(errno) << endl;
        exit(-1);

    }
}

void WriteFifo(int fd)
{
    char buf[64];
    snprintf(buf,sizeof(buf),"Hello myfifo\n");
    int n = write(fd,buf,sizeof(buf));
    if(n == -1)
    {
        cout << "errno = " << errno << ", " << strerror(errno) << endl;
        exit(-1);

    }
    cout << "我写入了 " << n << endl;
}

void test()
{
    // 在虚拟机的共享目录下创建不了命名管道,我们需要去虚拟机自己的linux目录创建
    if(mkfifo(fifo.c_str(),mode) == -1)
    {
        cout << "errno = " << errno << ", " << strerror(errno) << endl;
        exit(-1);
    }

    int wfd = open(fifo.c_str(),O_WRONLY);
    if(wfd == -1)
    {
        cout << "errno = " << errno << ", " << strerror(errno) << endl;
        exit(-1);
    }
    int rfd = open(fifo.c_str(),O_RDONLY);
    if(rfd == -1)
    {
        cout << "errno = " << errno << ", " << strerror(errno) << endl;
        exit(-1);
    }
    // 一个进程同时以读写方式打开命名管道
    // 看是否会被阻塞住
    WriteFifo(wfd);
    // 重新定位文件指针到文件开头
    lseek(wfd, 0, SEEK_SET);
    ReadFifo(rfd);
}

void test1()
{
    // 在虚拟机的共享目录下创建不了命名管道,我们需要去虚拟机自己的linux目录创建
    if(mkfifo(fifo.c_str(),mode) == -1)
    {
        cout << "errno = " << errno << ", " << strerror(errno) << endl;
        exit(-1);
    }
    cout << "-------------" << endl;
   
    int wfd = open(fifo.c_str(),O_WRONLY);
    cout << "-------------" << endl;
    if(wfd == -1)
    {
        cout << "errno = " << errno << ", " << strerror(errno) << endl;
        exit(-1);
    }
    // 一个进程同时以读写方式打开命名管道
    // 看是否会被阻塞住
    cout << "-------------" << endl;
    WriteFifo(wfd);
    cout << "-------------" << endl;
    int rfd = open(fifo.c_str(),O_RDONLY);
    if(rfd == -1)
    {
        cout << "errno = " << errno << ", " << strerror(errno) << endl;
        exit(-1);
    }
    ReadFifo(rfd);
    unlink(fifo.c_str());
}

// 在同一个进程内部使用命名管道必须以读写的方式打开命名管道
// 不可以分别以读方式打开，以写方式打开
// 原因是：命名管道底层设置的同步机制，只有当两端同时打开的时候，命名管道才能开始通信
void test2()
{
    if(mkfifo(fifo.c_str(),mode) == -1)
    {
        cout << "errno = " << errno << ", " << strerror(errno) << endl;
        exit(-1);
    }
    int fd = open(fifo.c_str(),O_RDWR);
    if(fd == -1)
    {       
        cout << "errno = " << errno << ", " << strerror(errno) << endl;
        exit(-1);
    }
    WriteFifo(fd);
    // 改变读写指针的位置
    lseek(fd,0,SEEK_SET);
    ReadFifo(fd);
    close(fd);
    unlink(fifo.c_str());
}


void server()
{
    // 创建命名管道
    if(mkfifo(fifo.c_str(),mode) == -1)
    {
        cout << "errno = " << errno << ", " << strerror(errno) << endl;
        exit(-1);
    }
    cout << "命名管道创建成功" << endl;
    // 以写的方式打开命名管道
    int wfd = open(fifo.c_str(),O_WRONLY);
    if(wfd == -1)
    {
        cout << "errno = " << errno << ", " << strerror(errno) << endl;
        exit(-1);
    }
    // 会等待读端被打开，如果读端为打开则阻塞
    int cnt = 0;
    while(true)
    {
        char buf[64];
        snprintf(buf,sizeof(buf),"server# 我在发送消息 %d\n",cnt);
        cout << buf << endl;
        write(wfd,buf,sizeof(buf));
        cnt++;
        if(cnt == 5)
            break;
        sleep(1);
    }
    //关闭命名管道
    unlink(fifo.c_str());
    cout << "关闭命名管道" << endl;

}
int main()
{
    server();
    return 0;
}
